---
description: Placeholder Placeholder Placeholder Placeholder Placeholder Placeholder
---

import { Callout } from '@theguild/components'

# Preparing for Production

Shipping GraphQL Yoga to production requires you to make some decisions about how you want to deploy
your API and how you want to protect it. If you need to serve a lot of traffic, you might also need
to consider caching.

## Security

GraphQL by design offers you a full query language engine for fetching data from your API. This
means that you can write queries that are very complex and can be very expensive to execute. This
could be abused by malicious users to perform various attacks on your API.

Depending on the purpose and use-case of the GraphQL API you can take different approaches to
protect your API.

### Private API

If your API is private and you are the only consumer of the API, you can use persisted operations to
ensure that only the operations you use are allowed to be executed.

Persisted Operations is a technique in which you extract the GraphQL operations from the client
during the deployment, assign them a hash and then also store the hash and the associated operation
directly on the GraphQL server or an external store from which the GraphQL server reads the
operations.

When a client sends a request to the server, it will send the hash of the operation it wants to
execute. The server will then look up the operation associated with the hash and execute it. With
this constraint only the operations you have persisted can be executed.

Follow the [Persisted Operations](/docs/features/persisted-operations) guide to learn how to use
this technique.

### Public API

When building a public API, you can't use persisted operations as you don't know which operations
your clients will send. Instead you must use more complex techniques to protect your API.

Our recommendation is to use the GraphQL Armor library to protect your API. For Yoga we recommend to
use the following plugins.

- [Cost Limit](https://escape.tech/graphql-armor/docs/plugins/cost-limit)
- [Max Tokens](https://escape.tech/graphql-armor/docs/plugins/max-tokens)
- [Max Aliases](https://escape.tech/graphql-armor/docs/plugins/max-aliases)
- [Max Depth](https://escape.tech/graphql-armor/docs/plugins/max-depth)
- [Max Directives](https://escape.tech/graphql-armor/docs/plugins/max-directives)

You can read more about these plugins in the
[GraphQL Armor documentation](https://escape.tech/graphql-armor/docs/category/plugins).

<Callout>
  Depending on the type/complexity of GraphQL operations that are executed you might need to adjust
  the configuration of the plugins. Please refer to the GraphQL Armor documentation for more
  information.
</Callout>

```ts filename="Simple escape security setup"
import { createYoga } from 'graphql-yoga'
import { costLimitPlugin } from '@escape.tech/graphql-armor-cost-limit'
import { maxAliasesPlugin } from '@escape.tech/graphql-armor-max-aliases'
import { maxDepthPlugin } from '@escape.tech/graphql-armor-max-depth'
import { maxDirectivesPlugin } from '@escape.tech/graphql-armor-max-directives'
import { maxTokensPlugin } from '@escape.tech/graphql-armor-max-tokens'

export const yoga = createYoga({
  plugins: [
    costLimitPlugin(),
    maxTokensPlugin(),
    maxDepthPlugin(),
    maxDirectivesPlugin(),
    maxAliasesPlugin()
  ]
})
```

## Caching

GraphQL Yoga by default has a built-in cache for parsing and validating GraphQL operations that are
executed. However, sometimes you might want to instead also cache the results of the GraphQL
operations.

This is especially useful if you have a lot of traffic and you want to reduce the load on your
underlying services and/or databases. Our recommended way of caching is to use the
[Yoga Response Cache Plugin](/docs/features/response-caching).

## Error Reporting

In order to get notified when your GraphQL API is throwing errors, you can use an external service
such as Sentry for making sure these errors don't go unnoticed. The
[Sentry plugin for Yoga (Envelop)](https://the-guild.dev/graphql/envelop/plugins/use-sentry), helps
you getting started quickly.

## Performance

Node.js comes with a built-in HTTP server implementation in `node:http` module. But you can use a
faster alternative which is [µWebSockets.js](/docs/integrations/integration-with-uwebsockets) to
`node:http` module. Even if it sounds like a WebSockets-only library, it can be used as a HTTP
server as well.

[See benchmarks](https://github.com/uNetworking/uWebSockets/tree/master/benchmarks#benchmark-driven-development)
[See how to integrate with uWebSockets.js](/docs/integrations/integration-with-uwebsockets)

But keep on mind, you won't be able to use `node:http` specific libraries on top of µWebSockets.js.
For example, you won't be able to use `express` or `koa` on top of µWebSockets.js.
